package NG::Sys::Cfg;
use strict;
use warnings;
use utf8;

use Cwd qw(realpath);

use base 'Exporter';
my %configs;
our $path = "../../data/cfg";
our @EXPORT = qw(config appconfig);

sub config {
	my ($name) = @_;
	$name ||= "main";
	my $config;
	if($config = $configs{$name}){
		return $config;
	}
	my $fn = $path."/".$name.".cfg";
	my $str = "";
	local *F;
	if(open F,$fn){
		binmode F,":utf8";
		local $/;
		$str = <F>;
		close F;
	}
	eval "# line 1 $name\n\$config = {".$str."}";
	if($@){
		die "$fn: $@";
	}
	return $configs{$name} = $config;
}
sub appconfig{
	local $path = "../../data/cfgapp";
	return config(@_);
}
sub reference {
	my $name = shift;
	my $map = shift;
	my $filter = shift;
	tie my @ary,'LazyReference',$name,$map,$filter;
	return \@ary;
}
sub lazy_config {
	my $name = shift;
	my $value = shift;
	tie my %hash,'LazyConfig',$name,$value;
	return \%hash;
}

package LazyReference;
sub TIEARRAY{
	my $class = shift;
	my $name = shift;
	my $map = shift;
	my $filter = shift;

	unless($name){
		die "need name";
	}
	unless($map){
		die "need map";
	}
	unless(!ref $map || ref $map eq "HASH"){
		die "need map is ref or scalar";
	}
	
	return bless {
			name => $name,
			map => $map,
			filter => $filter,
		}, $class;
}
sub FETCH{
	my $self = shift;
	my $index = shift;
	return $self->check->[$index];
}
sub FETCHSIZE{
	my $self = shift;
	return scalar @{$self->check};
}
sub check {
	my $self = shift;
	unless($self->{list}){
		require NG::Sys::App;
		my $ref = NG::Sys::App::app()->reference($self->{name});
		my $list = $ref->get_list($self->{filter});
		my @list;
		unless(ref $self->{map}){
			my $v = $self->{map};
			for my $row(@$list){
				push @list,$row->{$v};
			}
		}else{
			my @k = keys %{$self->{map}};
			my @v = @{$self->{map}}{@k};
			push @list,{map {$_=>''} @k};
			for my $row(@$list){
				my %h;
				@h{@k} = @{$row}{@v};
				push @list,\%h;
			}
		}
		$self->{list} = \@list;
	}
	return $self->{list};
}

package LazyConfig;
sub TIEHASH{
	my $class = shift;
	my $name = shift;
	my $value = shift;

	unless($name){
		die "need name";
	}
	unless($value){
		die "need value";
	}
	
	return bless {
			name => $name,
			value => $value,
		}, $class;
}
sub FETCH {
	my $self = shift;
	my $key = shift;
	return $self->check->{$key};
}
sub SCALAR {
	my $self = shift;
	return scalar %{$self->check};
}
sub FIRSTKEY {
	my $self = shift;
	my $h = $self->check;
	my $a = keys %$h;
	return each %$h;
}
sub NEXTKEY {
	my $self = shift;
	my $h = $self->check;
	return each %$h;
}
sub check {
	my $self = shift;
	unless($self->{hash}){
		$self->{hash} = NG::Sys::Cfg::config($self->{name})->{$self->{value}};
	}
	return $self->{hash};
}

1;
